package odl;

import java.util.Vector;

public class Interface extends OdlElement {

	private Vector<Relation> relations;
	private Vector<Attribute> attributes;
	private Vector<String> keys_unreferenced;
	private Vector<String> inheritences;
	private Vector<Interface> children_interfaces; 
	private Vector<Operation> operations;
	private Vector<Interface> parents_interfaces;
	/**
	 * @return the extending_interfaces
	 */
	public Vector<Interface> getExtending_interfaces() {
		return parents_interfaces;
	}

	private Vector<Metric> metrics;



	public Interface(String _name) {
		super(_name);
		attributes = new Vector<Attribute>();
		relations = new Vector<Relation>();
		keys_unreferenced = new Vector<String>();
		inheritences = new Vector<String>();
		operations = new Vector<Operation>();
		children_interfaces = new Vector<Interface>();
		parents_interfaces = new Vector<Interface>();
		metrics = new Vector<Metric>();
	}
	
	/**
	 * @return the extended_interfaces
	 */
	public Vector<Interface> getExtended_interfaces() {
		return children_interfaces;
	}

	/**
	 * @return the keys_unreferenced
	 */
	public Vector<String> getKeys_unreferenced() {
		return keys_unreferenced;
	}

	public boolean equals(Interface I){
		boolean res = true;
		for (Attribute a : I.getAttributes()){
			res &= attributes.contains(a);
		}
		for (Relation r : I.getRelations()){
			res &= relations.contains(r);
		}
		for (String s : I.getKeys_unreferenced()){
			res &= keys_unreferenced.contains(s);
		}
		for (Operation o : I.getOperations()){
			res &= operations.contains(o);
		}
		for (Interface i1: I.getExtended_interfaces()){
			res &= children_interfaces.contains(i1);
		}
		for (Interface i2: I.getExtending_interfaces()){
			res &= parents_interfaces.contains(i2);
		}
		res &=  I.getAttributes().size() == attributes.size()
				&& I.getRelations().size() == relations.size()
				&& I.getKeys_unreferenced().size() == keys_unreferenced.size()
				&& I.getOperations().size() == operations.size()
				&& I.getExtended_interfaces().size() == children_interfaces.size()
				&& I.getExtending_interfaces().size() == parents_interfaces.size();
		return res;
	}

	public void addAttribute(Attribute _at)
	{
		attributes.add(_at);
	}

	public void addInheritence(String s)
	{
		inheritences.add(s);
	}

	public void addKey_unreferenced(String _s)
	{
		keys_unreferenced.add(_s);
	}

	public void addOperation(Operation op){
		operations.add(op);
	}

	public void addRelation(Relation _re)
	{
		relations.add(_re);
	}

	public Attribute getAttribute(String s)
	{
		for(Attribute a : attributes)
		{
			if(a.getName().equals(s))
				return a;
		}
		return null;

	}

	public Vector<String> getAttributesNames(){
		Vector<String> res = new Vector<String>();
		for (Attribute at : attributes)
		{
			res.add(at.getName());
		}
		return res;
	}

	public Vector<String> getDetails(){
		Vector<String> res = (Vector<String>) inheritences.clone();
		int i = res.size();
		if (i != 0) res.add(0, "Inheritences :");
		return res;
	}

	public Operation getOperation(String s)
	{
		for(Operation op : operations)
		{
			if(op.getName().equals(s))
				return op;
		}
		return null;

	}

	public Vector<String> getOperationsNames(){
		Vector<String> res = new Vector<String>();
		for (Operation op : operations)
		{
			res.add(op.getName());
		}
		return res;
	}

	public Relation getRelation(String s)
	{
		for(Relation re : relations)
		{
			if(re.getName().equals(s))
				return re;
		}
		return null;

	}

	public Vector<String> getRelationsNames(){
		Vector<String> res = new Vector<String>();
		for (Relation re : relations)
		{
			res.add(re.getName());
		}
		return res;
	}

	private boolean isKey(String name){
		return keys_unreferenced.contains(name);
	}

	public void updateContent(){
		for(Attribute a : attributes){
			a.updateContent(isKey(a.getName()));
		}
		for(Relation r : relations){
			r.updateContent(isKey(r.getName()));
		}
		for(String s : inheritences){
			Interface I = Controller.getController().get_Schema().getInterface(s);
			children_interfaces.add(I);
			I.addExtending_Interface(this);
			for(Relation r : I.getRelations())
				if(!relations.contains(r))
					relations.add(r);
			for(Operation o : I.getOperations())
				if(!operations.contains(o))
					operations.add(o);
			for(Attribute a : I.getAttributes())
				if(!attributes.contains(a))
					attributes.add(a);
		}

	}

	public void calculateMetrics()
	{
		for(int i=0;i<10;i++)
			metrics.add(new Metric(i,this));
	}
	
	public void addExtending_Interface(Interface I)
	{
		parents_interfaces.add(I);
	}

	public int distanceTo(Interface I) throws Exception
	{
		return distanceTo(I,0);
	}

	public int distanceTo(Interface I, int dir) throws Exception
	{
		if(this.equals(I))
			return 0;
		int min = Integer.MAX_VALUE;
		switch(dir)
		{
		case 0 : 
		{

			for(Interface PI : this.parents_interfaces)
			{
				try{min = java.lang.Math.min(min, PI.distanceTo(I,1)+1);}
				catch(Exception e){}
			}
			for(Interface CI : this.children_interfaces)
			{
				try{min = java.lang.Math.min(min, CI.distanceTo(I,-1)+1);}
				catch(Exception e){}
			}
		}break;

		case 1 :
		{

			for(Interface PI : this.parents_interfaces)
			{
				try{min = java.lang.Math.min(min, PI.distanceTo(I,1)+1);}
				catch(Exception e){}
			}
		}break;
		case -1 :
		{

			for(Interface CI : this.parents_interfaces)
			{
				try{min = java.lang.Math.min(min, CI.distanceTo(I,-1)+1);}
				catch(Exception e){}
			}
		}break;
		default :
			min = -1;
		}

		if(min == Integer.MAX_VALUE)
			throw new Exception("Interface not found");
		return min;
	}

	/**
	 * @return the relations
	 */
	public Vector<Relation> getRelations() {
		return relations;
	}

	/**
	 * @return the attributes
	 */
	public Vector<Attribute> getAttributes() {
		return attributes;
	}

	/**
	 * @return the inheritences
	 */
	public Vector<String> getInheritences() {
		return inheritences;
	}

	/**
	 * @return the operations
	 */
	public Vector<Operation> getOperations() {
		return operations;
	}

	public int getChildrenCount()
	{
		return getDescendants().size();
	}
	
	public Vector<String> getMetricsStrings()
	{
		Vector <String> res = new Vector<String>();
		for(Metric m : metrics)
			res.add(m.toString());
		return res;
		
	}
	public Vector<Interface> getDescendants(){
		Vector<Interface> d = new Vector<Interface>();
		for (Interface i : children_interfaces){
			Vector<Interface> d2 = i.getDescendants();
			for (Interface i2 : d2){
				if (!d.contains(i2))
					d.add(i2);
			}
		}
		return d;
	}
	
	public Vector<Interface> getRelatedInterfaces(boolean iskey){
		Vector<Interface> res = new Vector<Interface>();
		for (Relation r : relations){
			if(iskey && r.getKey() || !iskey){
				Interface i = r.getTargeted_interface();
				if (!i.equals(this) && !res.contains(i))
					res.add(i);
			}
		}
		return res;
	}
	
	public float[] getMetricsValues()
	{
		float[] metricsValues = new float[10];
		int i=0;
		for(Metric m :  metrics)
			metricsValues[i++]=m.getValue();
		return metricsValues;
	}
}
